from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app
import simplejson as json
from models import User_Dish
from math import *

""" This class is responsible of checking if the user did rate a specific dish or not
    If the dish is already rated by the user the system overrides the user old rate with
    the new one else add the rate as a new entity.
    And changes the average rate and number of users who rated the dish
     and returns it to the app """
class rate(webapp.RequestHandler):

    def post(self):
        user = self.request.get('id')
        rate = self.request.get('rvalue')
        dish = self.request.get('dish')
        self.response.headers['Content-Type'] = 'text/plain'
#        self.response.out.write(user)
        id=db.GqlQuery("SELECT __key__ from User WHERE android_id = :1",user)
#        self.response.out.write("got the user")
        for i in id:
            theUser=db.get(i)
        theDish=db.get(dish)
        q=db.GqlQuery("SELECT __key__ from  User_Dish where user = :1 AND dish = :2",theUser.key(),theDish.key())
        average=theDish.av_rate * theDish.no_rate
        theRate=int(float(rate))
        if q.count() == 0:
            theDish.no_rate=theDish.no_rate+1
            User_Dish(user=theUser.key(),dish=theDish.key(),rate=theRate).put()
            average=average+theRate
#            self.response.out.write("To add new record in db \n")
        else:
#            self.response.out.write("Edit record \n")
            for r in q:
                edit_rate=db.get(r)
                average=average+theRate-edit_rate.rate
                edit_rate.rate=theRate
                edit_rate.put()
        temp = average/theDish.no_rate
#        self.response.out.write("average change %d"%(temp))        
        theDish.av_rate=temp
        theDish.put()
        result = {'average':float(theDish.av_rate), 'num':int(theDish.no_rate)}
#        self.response.out.write("%dnumber%d"%(theDish.av_rate,theDish.no_rate))
        self.response.out.write(json.dumps(result))
        
class comment(webapp.RequestHandler):

    def post(self):
        dish = self.request.get('dish')
        comments=self.request.get('comment')
        commentsList=comments.split('\n');
        theDish=db.get(dish)
        theDish.comments=commentsList
        theDish.put()
#        result = {'com':[str(d) for d in theDish.comments]}       
#        self.response.out.write(json.dumps(result))

  
class near(webapp.RequestHandler):
    """
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    """
    def haversine(self,lon1, lat1, lon2, lat2):
    
    # convert decimal degrees to radians 
        lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
        dlon = lon2 - lon1 
        dlat = lat2 - lat1 
        a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
        c = 2 * asin(sqrt(a)) 
        km = 6367 * c
        return km 
    
    """ This method is used to get the dishes near the user
    The user location longitude,latitude and the service used to get the user location 
    is received in the request. 
    The service the user location was detected with is need to 
    determine the max distance for dish to be near
    The distance between the user and the dish is calculated using haversine formula """      
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        lng = float(self.request.get('lng'))
        lat = float(self.request.get('lat'))
        by = self.request.get('by')
#        self.response.out.write("lng1 %f" %lng )
#        self.response.out.write("lat1 %f \n" %lat )
#        self.response.out.write("GPS or NET = %s  \n" %by )
        dishes = db.GqlQuery("SELECT * from Dish")
        d_queries = []
        if by == 'GPS':
            const = float(1.8)
        else:
            const = float(2.5)
        self.response.out.write("diff %f  \n" %const )
         
        for rest in dishes:
            d=db.get(rest.restaurant.key())
            for i in range(len(d.location)):
                dish_lng = float(d.locationLong[i])    
                dish_lat = float(d.locationLat[i])
                distance = self.haversine(lng, lat, dish_lng, dish_lat)
#                self.response.out.write("lng2 %f \n" %dish_lng )
#                self.response.out.write("lat2 %f \n" %dish_lat )
#                self.response.out.write("distance %f \n" %distance )
                if distance <= const:
                    d_queries.append(rest)
#                    
#                self.response.out.write("lng2 %f \n" %dish_lng )
#                self.response.out.write("lngd %f" %float(lng-const) )
#                self.response.out.write("lngd %f \n" %float(lng+const) )
#                
#                if dish_lng>=float(lng-const) and dish_lng<=float(lng+const):
#                    self.response.out.write("lat2 %f \n" %dish_lat )
#                    self.response.out.write("latd %f" %float(lat-const) )
#                    self.response.out.write("latd %f \n" %float(lat+const) )
#                    if dish_lat >= float(lat-const) and dish_lat <= float(lat+const):
#                        #self.response.out.write("satisfy \n")
#                        d_queries.append(rest)
        result = [{'name': str(q.name), 'rate': int(q.rate),'key':str(q.key())} for q in d_queries]
        self.response.out.write(json.dumps(result))  
        
application = webapp.WSGIApplication([('/func/rate', rate),('/func/near', near),('/func/comment', comment)],debug=True)
  
def main():
    run_wsgi_app(application)
    
if __name__ == "__main__":
    main()